﻿using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Rechargeable.Machines.Dto;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using System.Linq;
using Rechargeable.Products;
using Volo.Abp.Identity;
using Microsoft.AspNetCore.Identity;
using Volo.Abp;
using Microsoft.AspNetCore.Authorization;
using Rechargeable.Products.Dtos;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Identity.AspNetCore;

namespace Rechargeable.Machines
{
    public class MachineAppService : CrudAppService<
        Machine, MachineDto, Guid, PagedAndSortedResultRequestMachineDto,
        CreateUpdateMachineDto,
        CreateUpdateMachineDto>, IMachineAppService
    {
        IdentityUserManager _identityUserManager;
        AbpSignInManager _signInManager;
        private readonly IRepository<Product, Guid> _repositoryProduct;
        private readonly IRepository<SerialNumber, Guid> _repositorySerialNumbers;

        public MachineAppService(IRepository<Machine, Guid> repository,
            IRepository<Product, Guid> repositoryProduct,
                   IRepository<SerialNumber, Guid> repositorySerialNumbers,
            IdentityUserManager identityUserManager,
            AbpSignInManager signInManager) : base(repository)
        {
            _repositoryProduct = repositoryProduct;
            _repositorySerialNumbers = repositorySerialNumbers;
            _identityUserManager = identityUserManager;
            _signInManager = signInManager;
        }


        /// <summary>
        /// 验证过期时间
        /// </summary>
        /// <param name="inputCheckExpireTimeDto"></param>
        /// <returns></returns>
        [Route("api/app/machine/checkExpireTime")]
        [Route("api/app/machine/check-expire-time")]
        public async Task<GetExpireTimeDto> GetCheckExpireTime(InputCheckExpireTimeDto inputCheckExpireTimeDto)
        {
            ///api/app/machine/check-expire-time
            //查找商品是否存在
            var product = (await _repositoryProduct.GetQueryableAsync()).Where(q => q.Id == inputCheckExpireTimeDto.ProductId).FirstOrDefault();
            if (product == null)
                return new GetExpireTimeDto() { Day = -3, IsExpireTime = false };

            if (string.IsNullOrEmpty(inputCheckExpireTimeDto.UserNameOrEmailAddress) || string.IsNullOrEmpty(inputCheckExpireTimeDto.Password))
            {
                ///用户名密码为空
                return new GetExpireTimeDto() { Day = -2, IsExpireTime = false };
            };

            var identityUser = await _identityUserManager.FindByNameAsync(inputCheckExpireTimeDto.UserNameOrEmailAddress);
            var loginResult = await _signInManager.CheckPasswordSignInAsync(identityUser, inputCheckExpireTimeDto.Password, true);
            if (loginResult.Succeeded)
            {
                //验证机器Drive 和Product
                var machine = (await Repository.GetQueryableAsync()).Where(q => q.DriveId == inputCheckExpireTimeDto.DriveId && q.ProductId == inputCheckExpireTimeDto.ProductId && q.UserId == identityUser.Id).FirstOrDefault();
                if (machine == null)
                {
                    var machineId = (await CreateAsync(new CreateUpdateMachineDto()
                    {
                        DriveId = inputCheckExpireTimeDto.DriveId,
                        ProductId = inputCheckExpireTimeDto.ProductId,
                        Name = inputCheckExpireTimeDto.MachineName,
                        UserId = identityUser.Id,
                        Desc = inputCheckExpireTimeDto.Desc,
                        LastOnlineTime = DateTime.Now,
                        AutoRecharge = true,
                        ExpireTime = DateTime.Now.AddMinutes(-10)
                    })).Id;
                    await CurrentUnitOfWork.SaveChangesAsync();
                    machine = await Repository.GetAsync(machineId);
                }

                if (machine.Name != inputCheckExpireTimeDto.MachineName)
                {
                    machine.Name = inputCheckExpireTimeDto.MachineName;
                    machine.Desc = inputCheckExpireTimeDto.Desc;
                }
                machine.LastOnlineTime = DateTime.Now;

                //获取剩余分钟数 
                int ExpireTime = Convert.ToInt32((machine.ExpireTime - DateTime.Now).TotalMinutes);
                //对剩余时间小于10分钟的机器进行自动充值
                if (ExpireTime < 10 && machine.AutoRecharge)
                {
                    await Recharge(machine);
                }
                await Repository.UpdateAsync(machine);
                ExpireTime = Convert.ToInt32((machine.ExpireTime - DateTime.Now).TotalMinutes);
                var ExpireTimeDay = ExpireTime / 60 / 24;
                return new GetExpireTimeDto() { IsExpireTime = ExpireTime > 0 ? true : false, Day = ExpireTimeDay, ProductId = product.Id, Version = product.Version, ExpireTime = machine.ExpireTime };
            }
            else
            {
                //登陆失败
                return new GetExpireTimeDto() { Day = -4, IsExpireTime = false };
            }
        }

        private async Task Recharge(Machine machine)
        {
            ////查询可用序列号,优先使用有到期时间的账号
            var serialNumber =  (await _repositorySerialNumbers.GetQueryableAsync()).Where(q => q.BuyUserId == machine.UserId && q.ProductId == machine.ProductId && q.UseTime == null && (q.MachineId == Guid.Empty || q.MachineId == null)).OrderBy(q => q.Expire).OrderBy(q => q.CreationTime).FirstOrDefault();
            if (serialNumber != null)
            {
                serialNumber.UseTime = DateTime.Now;
                serialNumber.MachineId = machine.Id;
                serialNumber.CreateDesc += $"\r\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}通过平台系统自动续费，机器号【{machine.Id}】。";
                if (machine.ExpireTime < DateTime.Now)
                {
                    machine.ExpireTime = DateTime.Now;
                }
                machine.ExpireTime = machine.ExpireTime.AddDays(serialNumber.Expire);
                machine.MachineRecords.Add(new MachineRecord()
                {
                    MachineId = machine.Id,
                    Desc = $"{DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")}使用【{serialNumber.Id}】序列号进行续费，增加时间【{serialNumber.Expire}】天,有效期到【{ machine.ExpireTime.ToString("yyyy-MM-dd ")}】该行为由系统自动续费完成。",
                });
                await _repositorySerialNumbers.UpdateAsync(serialNumber);
            }
        }

        /// <summary>
        /// 对账号进行解绑，并生成新的序列号。新的序列号记录有效日期
        /// </summary>
        /// <param name="driveId"></param>
        /// <param name="machineId"></param>
        /// <param name="productId"></param>
        /// <returns></returns>
        [Authorize]
        public async Task<Guid> Relieve(Guid machineId)
        {
            var machine = (await Repository.GetQueryableAsync()).Where(q => q.Id == machineId).FirstOrDefault();
            if (machine != null)
            {
                if (machine.ExpireTime > DateTime.Now)
                {
                    var sn = new SerialNumber();
                    sn.BuyUserId = machine.UserId;
                    sn.CreateDesc = $"\r\n{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},【{CurrentUser.UserName}】解绑机器【{machine.Id}】。";
                    sn.Expire = (machine.ExpireTime - DateTime.Now).Days;
                    sn.ProductId = machine.ProductId;
                    sn.ProductPriceId = Guid.Empty;
                    sn.MachineId = Guid.Empty;
                    await _repositorySerialNumbers.InsertAsync(sn);
                    machine.ExpireTime = DateTime.Now.AddDays(-1);
                    machine.AutoRecharge = false;
                    machine.MachineRecords.Add(new MachineRecord()
                    {
                        MachineId = machine.Id,
                        Desc = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")},【{CurrentUser.UserName}】对该机器进行解绑，生成的序列号【{sn.Id}】,剩余期限【{sn.Expire}】。",
                    });
                    await Repository.UpdateAsync(machine);
                    return sn.Id;
                }
                else
                {
                    machine.AutoRecharge = false;
                    machine.MachineRecords.Add(new MachineRecord()
                    {
                        MachineId = machine.Id,
                        Desc = $"【{CurrentUser.UserName}】对该机器进行解绑，因时间已经到期，未生成新的序列号。",
                    });
                    //throw new UserFriendlyException("解绑成功，因时间已经到期，未生成新的序列号");
                    return Guid.Empty;
                }
            }
            else
            {
                throw new UserFriendlyException("未找到机器信息");
            }
        }

        /// <summary>
        /// 获取已经使用的商品
        /// </summary>
        /// <returns></returns>
        [Authorize]
        public async Task<List<ProductDto>> GetUseProduct()
        {
            var productIds = (await Repository.GetQueryableAsync()).Where(q => q.UserId == CurrentUser.Id.Value).GroupBy(q => q.ProductId).Select(q => q.Key).ToList();
            var products = (await _repositoryProduct.GetQueryableAsync()).Where(q => productIds.Contains(q.Id)).ToList();
            return ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
        }

        protected override async Task<IQueryable<Machine>> CreateFilteredQueryAsync(PagedAndSortedResultRequestMachineDto input)
        {
            var query = await base.CreateFilteredQueryAsync(input);
            //if (AuthorizationService.IsGrantedAsync(Permissions.RechargeablePermissions.ShowAllMachine).Result == false)
            //{
            query = query.Where(q => q.UserId == CurrentUser.Id);
            //}
            if (input.ProductId.HasValue && input.ProductId.Value != Guid.Empty)
                query = query.Where(q => q.ProductId == input.ProductId.Value);
            if (!string.IsNullOrEmpty(input.Key))
            {
                query = query.Where(q => q.Name.Contains(input.Key) || q.Desc.Contains(input.Key));
            }
            return query;
        }

        public async Task AutoRecharge(Guid machineId)
        {
            var machine = (await Repository.GetQueryableAsync()).Where(q => q.Id == machineId).FirstOrDefault();
            if (machine != null && machine.UserId == CurrentUser.Id)
            {
                machine.AutoRecharge = true;
            }
            else
            {
                throw new UserFriendlyException("未找到机器信息或者机器信息不属于您");
            }

            await Task.CompletedTask;
        }
    }
}
